﻿#region Apache License Version 2.0
/*----------------------------------------------------------------

Copyright 2024 DJ Zheng & ShangHai GM Nahefa Technology Co.,Ltd.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied. See the License for the specific language governing permissions
and limitations under the License.

----------------------------------------------------------------*/
#endregion Apache License Version 2.0

using System.IO;
using System.Linq;
using System.Text;
using System.Threading;  // use to sleep
using Collector.Device;

namespace Collector
{
    public class PulseContinuous : PulseGeneralCollector
    {
        private readonly byte CMD_OFFSET = 0x05;
        private IDeviceCommunication mDeviceCommunication;        
        private AutoResetEvent conditionWait = new AutoResetEvent(false);
        private bool isFactoryTestMode = false;
        private bool isRapidPhaseFinished = false;
        // 指示连续采脉状态转换
        private ContinuousState mState;
        // 指示设备反馈的真实状态码
        private ContinuousResponseCode mCode;
        // 脉象原始数据保留文件
        private string mRawDataFile;

        public delegate int PulseContinuousNotifyDelegate<T>(T obj, PulseCommonHelper.Display.DisplayType type);
        public PulseContinuousNotifyDelegate<PulseCommonHelper.Display> notifyMainForm;

        public enum ContinuousState
        {
            /// <summary>
            /// 应用程序出现严重错误(程序已经无法正常运行)
            /// </summary>
            eCONTINUOUS_STATE_IDLE,
            /// <summary>
            /// 应用程序进行调试的信息
            /// </summary>
            eCONTINUOUS_STATE_STARTED,
            /// <summary>
            /// 应用程序运行过程的信息
            /// </summary>
            eCONTINUOUS_STATE_PREPARE_MEASURING,
            /// <summary>
            /// 应用程序可能存在潜在错误的信息
            /// </summary>
            eCONTINUOUS_STATE_MEASURING,
            /// <summary>
            /// 应用程序出现错误(程序仍可继续运行)
            /// </summary>
            eCONTINUOUS_STATE_FINISHED,
            /// <summary>
            /// 作为单独消息输出 不存log的一个标志
            /// </summary>
        }

        public enum ContinuousResponseCode
        {
            eCODE_RAPID_FINISHED = 0x00,
            eCODE_CONTINUOUS_NORMAL_FINISHED,
            eCODE_CONTINUOUS_FINISHED_WITH_TIMEOUT,
            eCODE_RAPID_WITH_TIMEOUT,
            eCODE_RAPID_ACK_WITH_TIMEOUT = 0x04,
            eCODE_DEVICE_OVERRIDE = 0xA6
        }

        public PulseContinuous()
        {
            
        }

        public IDeviceCommunication DeviceCommunication
        {
            get { return mDeviceCommunication; }
            set { DeviceAdapter = mDeviceCommunication = value; }
        }

        public string RawDataFile
        {
            get { return mRawDataFile; }
            set { mRawDataFile = value; }
        }

        public bool ResetDevice()
        {
            return mDeviceCommunication.ResetDevice();
        }

        public bool ProcessContinuous()
        {
            // Send command to Device.
            byte[] payload;
            bool ret = mDeviceCommunication.SendCommandToDevice("SPHeadmmHg_ConsecutiveData", 0xD0, out payload);
            if (ret && payload[0] == 0x00)
            {
                string message = string.Format("->连续加压, Waiting for...");
                DisplayMessageToUI(message, LogMsgType.DEBUG);
                SetCollectorState(ContinuousState.eCONTINUOUS_STATE_STARTED);
            }
            else
            {
                ret = false;
            }

            return ret;
        }

        public override void ControlFrameProcessing(byte[] frame)
        {
            DeviceEvent evt = (DeviceEvent)frame[CMD_OFFSET];
            Log.Debug("control_frame: {0} evt code: {1}", ConvertFuncs.ByteArrayToHexString(frame), evt);
            switch (evt)
            {
                case DeviceEvent.eDEV_EVENT_CONTINUOUS:
                    {
                        // 回复设备收到D1事件
                        ProcessResponseData(frame, frame.Length);

                    }
                    break;
                case DeviceEvent.eDEV_EVENT_OVERFLOW:
                    {
                        // Check pump exceeding the maximum pressure value.
                        mCode = ContinuousResponseCode.eCODE_DEVICE_OVERRIDE;
                        SetCollectorState(ContinuousState.eCONTINUOUS_STATE_FINISHED);
                        string message = string.Format("->连续加压, 匀速加压过载");
                        DisplayMessageToUI(message, LogMsgType.DEBUG);
                    }
                    break;
                case DeviceEvent.eDEV_EVENT_RESET:
                    {
                        // 回复设备收到A4事件
                        if(mDeviceCommunication != null)
                        {
                            mDeviceCommunication.GivebackCompleted(evt);
                        }
                        
                        Log.Debug("ControlFrameProcessing device already reset completed");
                        // 更新状态
                        SetCollectorState(ContinuousState.eCONTINUOUS_STATE_IDLE);
                    }
                    break;
                default:
                    {
                        base.ControlFrameProcessing(frame);
                        break;
                    }
            }
            
        }

        public override void PulseFrameProcessing(byte[] frame) 
        {
            if (mState != ContinuousState.eCONTINUOUS_STATE_MEASURING)
            {
                return;
            }

            if(mRawDataFile != null)
                ByteToFile(frame, mRawDataFile);            
        }

        public override void AirFrameProcessing(byte[] frame) {
        
        }

        public void ResetContinuousConfigure()
        {
            isFactoryTestMode = false;
            isRapidPhaseFinished = false;
            mRawDataFile = null;
            mState = ContinuousState.eCONTINUOUS_STATE_IDLE;
            mCode = ContinuousResponseCode.eCODE_RAPID_FINISHED;
        }

        public void SetCollectorWorkMode(bool mode)
        {
            isFactoryTestMode = mode;
        }

        public void SetCollectorState(ContinuousState state)
        {
            switch(state)
            {
                case ContinuousState.eCONTINUOUS_STATE_IDLE:
                {
                   mState = state;
                }
                break;
                case ContinuousState.eCONTINUOUS_STATE_STARTED:
                {
                        mState = state;
                }
                break;
                case ContinuousState.eCONTINUOUS_STATE_PREPARE_MEASURING:
                {
                        mState = state;
                }
                break;
                case ContinuousState.eCONTINUOUS_STATE_MEASURING:
                {
                        mState = state;
                        string message = string.Format("->连续加压, 正在匀速加压,请等待...");
                        DisplayMessageToUI(message, LogMsgType.DEBUG);
                    }
                break;
                case ContinuousState.eCONTINUOUS_STATE_FINISHED:
                {
                        mState = state;
                }
                break;
            }
        }

        public ContinuousState GetContinuousState()
        {
            return mState;
        }

        public ContinuousResponseCode GetContinuousResponseCode(out string reason)
        {
            switch (mCode) {
                case ContinuousResponseCode.eCODE_RAPID_FINISHED:
                {
                    reason = "快速加压完成，等待主机响应";
                }
                break;
                case ContinuousResponseCode.eCODE_CONTINUOUS_NORMAL_FINISHED:
                {
                    reason = "测脉正常完成";
                }
                break;
                case ContinuousResponseCode.eCODE_CONTINUOUS_FINISHED_WITH_TIMEOUT:
                {
                    reason = "测脉超时完成";
                }
                break;
                case ContinuousResponseCode.eCODE_RAPID_WITH_TIMEOUT:
                {
                    reason = "快速加压超时";
                }
                break;
                case ContinuousResponseCode.eCODE_RAPID_ACK_WITH_TIMEOUT:
                {
                    reason = "快速加压完成，主机响应超时";
                }
                break;
                case ContinuousResponseCode.eCODE_DEVICE_OVERRIDE:
                {
                    reason = "加压过载";
                }
                break;
                default:
                    reason = "Unknow";
                    break;
            }

            return mCode;
        }

        public void ProcessResponseData(byte[] data, int size)
        {
            byte command = data[5];
            byte code = (size > 6)?data[6]:(byte)0x0;

            string dataString = ToHexStringStringBuilder(data);
            Log.Debug("ProcessResponseData size:" + size +
                            ", data: " + dataString);


            mCode = (ContinuousResponseCode)code;
            switch ((ContinuousResponseCode)code)
            {
                case ContinuousResponseCode.eCODE_RAPID_FINISHED:
                {
                    // 主机应答设备
                    mDeviceCommunication.SendCommandToDevice("SPResponseRapid_ConsecutiveData");

                    string message = string.Format("->连续加压, 快速加压正常完成，主机已响应");
                    DisplayMessageToUI(message, LogMsgType.DEBUG);

                    SetCollectorState(ContinuousState.eCONTINUOUS_STATE_MEASURING);
                }
                break;
                case ContinuousResponseCode.eCODE_CONTINUOUS_NORMAL_FINISHED:
                {
                    string message = string.Format("->连续加压, 匀速加压正常完成");
                    DisplayMessageToUI(message, LogMsgType.DEBUG);

                    SetCollectorState(ContinuousState.eCONTINUOUS_STATE_FINISHED);
                }
                break;
                case ContinuousResponseCode.eCODE_CONTINUOUS_FINISHED_WITH_TIMEOUT:
                {

                    string message = string.Format("->连续加压, 匀速加压超时完成");
                    DisplayMessageToUI(message, LogMsgType.DEBUG);
                    // Maybe to reset device
                    SetCollectorState(ContinuousState.eCONTINUOUS_STATE_FINISHED);
                }
                break;
                case ContinuousResponseCode.eCODE_RAPID_WITH_TIMEOUT:
                {
                    string message = string.Format("->连续加压, 快速加压超时");
                    DisplayMessageToUI(message, LogMsgType.DEBUG);
                    // Maybe to reset device
                    SetCollectorState(ContinuousState.eCONTINUOUS_STATE_FINISHED);

                }
                break;
                case ContinuousResponseCode.eCODE_RAPID_ACK_WITH_TIMEOUT:
                {
                    string message = string.Format("->连续加压, 快速加压完成，等待主机响应超时");
                    DisplayMessageToUI(message, LogMsgType.DEBUG);
                    // Maybe to reset device
                    SetCollectorState(ContinuousState.eCONTINUOUS_STATE_FINISHED);
                }
                break;
            }
        }

        private static bool ByteToFile(byte[] byteArray, string fileName)
        {
            bool result = false;
            byte[] padding = { 0x00, 0x00, 0x00, 0x00, 0x00 };
            try
            {
                using (FileStream fs = new FileStream(fileName, FileMode.Append, FileAccess.Write))
                {
                    fs.Write(byteArray, 0, byteArray.Length);
                    //fs.Write(padding, 0, 5);
                    result = true;
                }
            }
            catch
            {
                result = false;
            }
            return result;
        }

        private void DisplayMessageToUI(string message, LogMsgType type)
        {
            PulseCommonHelper.Display display = new PulseCommonHelper.Display();
            display.displayMsgBox.message = message;
            display.displayMsgBox.type = type;
            if (notifyMainForm != null)
            {
                notifyMainForm(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_MSG);
            }
        }

        private void DisplayMessageToUI(string itemName, string itemInfo, bool result)
        {
            PulseCommonHelper.Display display = new PulseCommonHelper.Display();
            display.displayRltBox.itemName = itemName;
            display.displayRltBox.itemInfo = itemInfo;
            display.displayRltBox.result = result;
            if (notifyMainForm != null)
            {
                notifyMainForm(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_ITEM);
            }
        }

        private string ToHexStringStringBuilder(byte[] bytes)
        {
            StringBuilder hex = new StringBuilder(bytes.Length * 2);
            foreach (byte b in bytes)
            {
                hex.AppendFormat("{0:x2} ", b);
            }
            return hex.ToString();
        }
    }
}
